#pragma once
#include <vector>
#include "Command.h"
#include "ENet.h"

class TcpServer
{
public:
	struct ServerEntity // server side version of "entity" type
	{
		int Type;
		int SpawnTime;
		char Spawned;
	};
	typedef std::vector<ServerEntity> ServerEntityList;

	struct Client // server side version of "dynent" type
	{
		int type;
		int num;
		ENet::ENetPeer *peer;
		std::string hostname;
		void *info;
	};
	typedef std::vector<Client> ClientList;

	struct ClientInfo
	{
		bool accept;
		SHORT PosX, PosY, PosZ;
		SHORT RotX, RotY;
	};
	typedef std::vector<ClientInfo*> ClientInfoList;

public:
	TcpServer();
	~TcpServer();

	WORD getServerPort() const { return mServerPort; }
	WORD getServerInfoPort() const { return mServerPort + 1; }
	WORD getLanInfoPort() const { return mServerPort + 2; }

	bool Listen(WORD port, int maxClients = MAXCLIENTS);
	void CleanUp();

	void ResetItems();

	void Update(float elapsedTime);

	// reply all server info requests
	void CheckServerSockets();
	void ServerInfoReply(void* buff, size_t len);

	// send.
	bool SendPackets();
	void SendMessage(int n, const Command* cmd, size_t len);
	void SendMessageToAll(const Command* cmd, size_t len, int exclude = -1);

	// receive.
	void ClientPosition(int sender, const Command* cmd, size_t len);
	void ClientMessage(int sender, const Command* cmd, size_t len);
	void ReceivePacket(ENet::ENetPacket *packet, int sender, int channel);

	// client.
	Client& AddClient();
	ClientInfo* NewClientInfo();
	void DeleteClientInfo(ClientInfo* info);
	int ClientConnect(int n, DWORD ip);
	void ClientDisconnect(int n);
	void DisconnectClient(int n, int reason);

private:
	void SendPacket(int n, int channel, const Command* cmd, size_t len, int exclude = -1, DWORD flag = ENet::ENET_PACKET_FLAG_RELIABLE);
	void SendPacket(int n, int channel, ENet::ENetPacket *packet, int exclude = -1);

private:
	WORD mServerPort;
	ENet::ENetHost* mServerHost;
	ENet::ENetSocket mPongSock;
	ENet::ENetSocket mLanSock;
	ServerEntityList mServerEntities;

	ClientList mClients;

	ClientInfoList mConnects;
	ClientInfoList mBots;
};
